Android UDP 通信总结 (终于从坑中爬起来了)

您所在的位置:网站首页 安卓 native收广播 Android UDP 通信总结 (终于从坑中爬起来了)

Android UDP 通信总结 (终于从坑中爬起来了)

2023-09-26 02:53| 来源: 网络整理| 查看: 265

2018.08.02 

最近做的项目要求为:一端为电视端,一端为手机端,实现电视端与手机端通过UDP进行通信。

解释:就是两个机器在同一个局域网内(即两端连接的同一个WiFi),可以通过UDP,一端将信息通过局域网散播出去后,在同一个局域网内的所有设备都能接收到信息,只不过,另一端对接收到的信息进行处理,这样就完成了UDP通信。发送信息方只负责发送信息,另一方只负责接收信息,两方还可以互相发送和接收信息,反正互不干扰,谁都不会管对方是否接收到信息。

 写的比较好的文章:https://blog.csdn.net/ITermeng/article/details/73482669?locationNum=9&fps=1。

想要了解更多关于UDP与TCP的基础知识,请看https://www.jianshu.com/p/cc62e070a6d2。

UDP通信步骤:

1、建立连接的IP地址和端口号,IP即是你想要发送的地址,端口号则要选用闲置端口就是向8000~9000这样的端口号。

2、建立DatagramSocket  sendSocket/receiveSocket ,用于发送和接受数据报文包。

3、创建报文包DatagramPacket sendPackage/receivePackage,将发送或接收的内容打包。

4、通过sendSocket.send(sendPackage)或者receiveSocket.receive(receivePackage),则完成了基于Socket的UDP通信。

注意事项:

1.同一端如果既要发送消息又想接收消息,一定要将发送的socket和接收的socket分开。不能用一个socket既接收信息,又发送信息,这样一定会造成阻塞。

2.接收线程中,一定要有  while(true){     if(标志何时结束)   代码块   }  这样的方式,不然,在接收信息时,一定会造成阻塞,就是只能接收到一次信息。

3.本来想开一个线程进行接收数据和发送数据,真的是太混乱了,所以大家还是开两个线程吧。。。。

具体代码:

服务端:

package com.example.admin.learnUdpCommunicateServer; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.util.ArrayList; import java.util.List; /** * @author zhou.jn */ public class UdpSocketServerActivity extends Activity { private static final String TAG = "SocketAutoConnectServer"; private static String IP; private static int BROADCAST_PORT = 9999; private static String BROADCAST_IP = "255.255.255.255"; private InetAddress inetAddress = null; private BroadcastThread broadcastThread; private DatagramSocket sendSocket = null; private DatagramSocket receiveSocket = null; private Button sendUDPBrocast; private volatile boolean isRuning = true; private TextView ipInfo; private Button btn_send; private EditText et_sendInfo; private String sendContent; private TextView tv_receive; private List ipList = new ArrayList(); private Button btnClear; private ReceiveThread receiveThread; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); initView(); initIp(); initThread(); try { inetAddress = InetAddress.getByName(BROADCAST_IP); } catch (Exception e) { e.printStackTrace(); } } private void initThread() { broadcastThread = new BroadcastThread(); broadcastThread.start(); receiveThread = new ReceiveThread(); receiveThread.start(); } private void initIp() { //Wifi状态判断 WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); if (wifiManager.isWifiEnabled()) { WifiInfo wifiInfo = wifiManager.getConnectionInfo(); IP = getIpString(wifiInfo.getIpAddress()); ipInfo.append(IP); System.out.println("IP IP:" + IP); } } private void initView() { ipInfo = (TextView) findViewById(R.id.ip_info); sendUDPBrocast = (Button) findViewById(R.id.sendUDPBrocast); tv_receive = findViewById(R.id.tv_receive); et_sendInfo = findViewById(R.id.et_sendContent); btn_send = findViewById(R.id.btn_sendInfo); try { receiveSocket = new DatagramSocket(BROADCAST_PORT); } catch (SocketException e) { e.printStackTrace(); } btn_send.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { sendMessageToThread(broadcastThread.mhandler); } }); btnClear = findViewById(R.id.btnClear); btnClear.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { tv_receive.setText(""); } }); sendUDPBrocast.setOnClickListener(new SendUDPBrocastListener()); } private void sendMessageToThread(Handler mhandler) { Message msg = Message.obtain(); sendContent = et_sendInfo.getText().toString(); msg.obj = sendContent; msg.what = 1; mhandler.sendMessage(msg); } /** * 将获取到的int型ip转成string类型 */ private String getIpString(int i) { return (i & 0xFF) + "." + ((i >> 8) & 0xFF) + "." + ((i >> 16) & 0xFF) + "." + (i >> 24 & 0xFF); } @SuppressLint("HandlerLeak") Handler myHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: { if (!msg.obj.equals(IP)) { if (!isExistIp(msg.obj.toString())) { ipList.add(msg.obj.toString()); } tv_receive.append(msg.obj.toString() + " 接收到信息 " + "\n"); } } break; default: break; } } }; public class SendUDPBrocastListener implements OnClickListener { @Override public void onClick(View v) { if (isRuning) { isRuning = false; sendUDPBrocast.setText("发送广播"); System.out.println("现在停止广播.."); } else { isRuning = true; sendUDPBrocast.setText("停止广播"); System.out.println("现在发送广播.."); } } } public class BroadcastThread extends Thread { private Handler mhandler = null; @SuppressLint("HandlerLeak") @Override public void run() { Looper.prepare(); mhandler = new Handler() { @Override public void handleMessage(Message msg) { String message = (String) msg.obj; byte[] data = message.getBytes(); DatagramPacket dpSend = null; dpSend = new DatagramPacket(data, data.length, inetAddress, BROADCAST_PORT); try { double start = System.currentTimeMillis(); for (int i = 0 ; i < 15; i ++) { sendSocket = new DatagramSocket(); sendSocket.send(dpSend); sendSocket.close(); Thread.sleep(80); Log.i(TAG, "sendMessage: data " + new String(data)); } double end = System.currentTimeMillis(); double times = end - start; Log.i(TAG, "receive: executed time is : "+ times +"ms"); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }; Looper.loop(); } } private boolean isExistIp(String revIp) { if (ipList != null && ipList.size() > 0) { for (String ip : ipList) { if (ip != revIp) { return false; } } } return false; } private class ReceiveThread extends Thread { @Override public void run() { while (true) { if (isRuning) { byte[] receiveData = new byte[1024]; DatagramPacket dpReceive = null; ipList.clear(); dpReceive = new DatagramPacket(receiveData, receiveData.length); try { receiveSocket.receive(dpReceive); } catch (IOException e) { e.printStackTrace(); } String recIp = dpReceive.getAddress().toString().substring(1); if (dpReceive != null) { Message revMessage = Message.obtain(); revMessage.what = 1; revMessage.obj = recIp; Log.i(TAG, "handleMessage: receive ip" + recIp); myHandler.sendMessage(revMessage); } } } } } @Override protected void onDestroy() { super.onDestroy(); isRuning = false; receiveSocket.close(); System.out.println("UDP Server程序退出,关掉socket,停止广播"); finish(); } }

客户端代码:

package com.example.admin.learnudpcommunicateclent; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import com.example.admin.udpclient.R; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; /** * @author zhou.jn */ public class SocketClientActivity extends Activity { private static int BROADCAST_PORT = 9999; private static final String TAG = "SocketConnectActivity"; private TextView ipInfo; private static String IP; private boolean isRunning = true; private Button btnBack; private DatagramSocket receiveSocket = null; private DatagramSocket sendSocket = null; private DatagramPacket dpReceive = null; private SendThread sendThread; private String previousContent = new String(); private Button btnClear; private String receiveIp; private String sendIp; @SuppressLint("HandlerLeak") Handler myHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: Log.i(TAG, "run handleMessage: "); ipInfo.append(msg.obj.toString() + "\n"); /**通过确认该客户端已经接收到信息后,再将自己的ip号码发送出去*/ new Thread(){ @Override public void run() { try { Thread.sleep(1500); /**开一个将前一次接收的内容置为空的线程,解决发送端两次发送相同的信息,接收端他可能就不会做处理的问题*/ previousContent = " "; } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); sendFeedBackToServer(sendThread.mHandler, msg.obj.toString()); break; case 2: ipInfo.append(msg.obj.toString()); default: break; } } }; private void sendFeedBackToServer(Handler mHandler, String ip) { Message msg = new Message(); msg.obj = ip; msg.what = 1; mHandler.sendMessage(msg); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ipInfo = findViewById(R.id.ip_info); btnBack = findViewById(R.id.btnBack); btnBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); btnClear = findViewById(R.id.btnClear); btnClear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ipInfo.setText(""); } }); ReceiveThread receiveThread = new ReceiveThread(); WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); if (wifiManager.isWifiEnabled()) { WifiInfo wifiInfo = wifiManager.getConnectionInfo(); IP = getIpString(wifiInfo.getIpAddress()); System.out.println("本机IP is :" + IP); } try { receiveSocket = new DatagramSocket(BROADCAST_PORT); sendThread = new SendThread(); sendThread.start(); receiveThread.start(); } catch (Exception e1) { e1.printStackTrace(); } } /** * 将获取到的int型ip转成string类型 */ private String getIpString(int i) { return (i & 0xFF) + "." + ((i >> 8) & 0xFF) + "." + ((i >> 16) & 0xFF) + "." + (i >> 24 & 0xFF); } private class ReceiveThread extends Thread { @SuppressLint("LongLogTag") @Override public void run() { while (true) { if (isRunning) { String receiveContent = null; byte[] buf = new byte[1024]; dpReceive = new DatagramPacket(buf, buf.length); try { receiveSocket.receive(dpReceive); receiveContent = new String(buf, 0, dpReceive.getLength()); Log.i(TAG, "run: receive message " + receiveContent); Log.i(TAG, "run: " + dpReceive.getAddress().toString()); receiveIp = dpReceive.getAddress().toString().substring(1); if (receiveIp != IP) { sendIp = receiveIp; } Log.i(TAG, "run:1 previousContent " + previousContent + " receiveContent " + receiveContent); if (!previousContent.equals(receiveContent) && !IP.equals(receiveIp)) { Message msg = myHandler.obtainMessage(); msg.obj = "服务器:" + sendIp + "发送的内容为:" + receiveContent; msg.what = 1; myHandler.sendMessage(msg); } previousContent = receiveContent; Log.i(TAG, "run:2 previousContent " + previousContent + " receiveContent " + receiveContent); } catch (IOException e) { e.printStackTrace(); } } } } } private class SendThread extends Thread { private Handler mHandler; @SuppressLint("HandlerLeak") @Override public void run() { Looper.prepare(); mHandler = new Handler() { @Override public void handleMessage(Message msg) { DatagramPacket dpSend = null; byte[] ip = IP.getBytes(); try { if (receiveIp != IP) { InetAddress inetAddress = InetAddress.getByName(sendIp); dpSend = new DatagramPacket(ip, ip.length, inetAddress, BROADCAST_PORT); } } catch (UnknownHostException e) { e.printStackTrace(); } try { String sendData = new String(ip, 0, dpSend.getLength()); sendSocket = new DatagramSocket(); sendSocket.send(dpSend); Log.i(TAG, "run: send message : " + sendData); sendSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }; Looper.loop(); } } @Override protected void onDestroy() { super.onDestroy(); receiveSocket.close(); isRunning = false; System.out.println("UDP Client程序退出,关掉socket,停止广播"); finish(); } }

刚开始做这个项目的疑惑及解决办法:

问题一:用一个DatagramSocket进行发送并接收信息,会不会有问题。

答:确实很有问题,所以一定要开(1+n)个DatagramSocket啊,同志们!一个DatagramSocket用于接收信息,另外n个是每次发送新消息的时候就新建一个DatagramSocket进行发送,发送后进行关闭。

问题二:当发送信息的时候,是想着每发送一个信息,就要关闭一个信息。可我想着发送完信息关闭后,接着又要发送消息怎么办?

答:每次新建DatagramSocket再进行关闭就可以啦!

问题三:想在客户端接收到信息后,发送给服务端告诉他我接收到信息了~,可是接收方只要监听端口就可以,不用IP的,那要如何获取接收端的IP呢?

答:通过接收数据包的dpReceive.getAddress()可以获取,并且它的格式为“/10.0.12.53”,所以要取子字符串subString(1)进行获取。

问题四:接收信息的时候咋能接收到自己发送的信息?

答:确实可以接收到自己发送的信息。。。。所以需要自行进行过滤处理,不要接收自己发送的信息,不然是不是会显得很傻。。

项目讲解:

服务器端:我怕客户端接收不到信息,所以我就发了15次信息,并且每次间隔80ms,这样客户端再接收不到信息,俺也没办法了,每次发送信息的时间大约为1200多ms,这么长时间总能接到一条吧,老兄!

                 发送端拨号为4个255,听说这样是可以发送给局域网,反正IP是个随意的大数就行,比如244.244.0.1都行~

客 户 端:服务器这老兄给我发这么多条相同的信息,我还每条都处理,是不是很傻!所以就进行判断我是不是重复接收了客户端的相同信息,如果相同,处理一次就够了。。。。

ps:UDP中没什么客户端,服务端,只是接收方,发送方而已,我只是这么称呼他们。。。

源码地址:https://download.csdn.net/download/weixin_37716758/10582295(优化的)

源码地址:https://download.csdn.net/download/weixin_37716758/10580690(带有APK)

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3